/*
 * Copyright (c) 2023 Cshoo Org. All Rights Reserved.
 */

package org.cshoo.tattoo.embed.domain.service;

import com.google.common.collect.Lists;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.cshoo.tattoo.embed.api.dto.AuthorityResp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author 杨翼
 * @since 1.0
 */
@Service
@Slf4j
public class AuthoritySdkService {

    @Resource
    private ApplicationContext applicationContext;

    @Value("${server.servlet.context-path}")
    private String contentPath;

    /**
     * 加载系统内的接口列表
     *
     * @return 接口列表
     */
    public List<AuthorityResp> loadAuthorities() {
        RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
        List<AuthorityResp> result = Lists.newArrayList();
        List<String> excludeBeanTypes = Lists.newArrayList(
                "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController",
                "springfox.documentation.swagger.web.ApiResourceController",
                "springfox.documentation.oas.web.OpenApiControllerWebMvc",
                "springfox.documentation.swagger2.web.Swagger2ControllerWebMvc",
                "org.cshoo.tattoo.embed.api.AuthoritySdkController");
        handlerMethods.forEach((k, v) -> {
            log.debug("k:{},v:{}", k, v);
            if (!excludeBeanTypes.contains(v.getBeanType().getName()) && Objects.nonNull(k) && Objects.nonNull(k.getPatternsCondition())) {
                Set<String> patterns = k.getPatternsCondition().getPatterns();
                Set<RequestMethod> methods = k.getMethodsCondition().getMethods();
                Method method = v.getMethod();
                if (CollectionUtils.isNotEmpty(patterns) && CollectionUtils.isNotEmpty(methods)) {
                    String pattern = patterns.stream().findFirst().orElse(StringUtils.EMPTY);
                    String httpMethod = methods.stream().findFirst().orElse(RequestMethod.TRACE).name();
                    AuthorityResp authority = new AuthorityResp();
                    String uri = contentPath + pattern;
                    log.debug("uri:{},httpMethod:{}", uri, httpMethod);
                    authority.setUri(uri);
                    authority.setMethod(httpMethod);
                    ApiOperation apiAnnotation = method.getAnnotation(ApiOperation.class);
                    Optional.ofNullable(apiAnnotation).ifPresent(aio -> authority.setName(aio.value()));
                    result.add(authority);
                }
            }
        });
        return result;
    }

}
